using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace XNAViewerSample
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class SkyboxComponent : Microsoft.Xna.Framework.DrawableGameComponent
        //Microsoft.Xna.Framework.GameComponent, Microsoft.Xna.Framework.IDrawable
    {
        //string[] Filenames;
        Effect effect;
        Model model;
        CameraComponent activeCamera;
        ContentManager contentLoader;

        public SkyboxComponent(Game game)
            : base(game)
        {
            this.DrawOrder = 0;
        }

        public Model SkyModel
        {
            get { return model; }
        }

        public CameraComponent ActiveCamera
        {
            set { activeCamera = value; }
        }

        public ContentManager ContentLoader
        {
            set { contentLoader = value; }
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
        }


        protected override void LoadContent()
        {
            effect = contentLoader.Load<Effect>("Shaders/SkySphere");
            model = contentLoader.Load<Model>("Models/Skybox/SphereHighPoly");
            TextureCube skyboxTexture = contentLoader.Load<TextureCube>("Models/Skybox/uffizi_cross");

            // Set the parameters of the effect
            effect.Parameters["ViewMatrix"].SetValue(activeCamera.ViewMatrix);
            effect.Parameters["ProjectionMatrix"].SetValue(activeCamera.ProjectionMatrix);
            effect.Parameters["SkyboxTexture"].SetValue(skyboxTexture);

            // Set the Skysphere Effect to each part of the Skysphere model
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = effect;
                }
            }

#if false
            Texture2D[] Sides = new Texture2D[6];
            
            //for (int i = 0; i < 6; i++)
            //{
            //    if (Filenames != null && !string.IsNullOrEmpty(Filenames[i]))
            //        Sides[i] = this.Game.Content.Load<Texture2D>(Filenames[i]);
            //}

            int x = 0;
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    Texture2D tex = ((BasicEffect)part.Effect).Texture;
                    part.Effect = effect.Clone(/*this.GraphicsDevice*/);
                    //if (Filenames != null && !string.IsNullOrEmpty(Filenames[x]))
                    //    tex = Sides[x];
                    part.Effect.Parameters["tex"].SetValue(tex);
                    x++;
                }
            }
#endif            
            base.LoadContent();
        }
#if false
        // Overrides not needed?

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
        }

#endif   
  
        //public void Draw(GameTime gameTime, Matrix projection, Matrix view, Vector3 position)
        public override void  Draw(GameTime gameTime)
        {
            if (this.Enabled)
            {
                // Set the View and Projection matrix for the effect
                effect.Parameters["ViewMatrix"].SetValue(activeCamera.ViewMatrix);
                effect.Parameters["ProjectionMatrix"].SetValue(activeCamera.ProjectionMatrix);
                // Draw the sphere model that the effect projects onto
                foreach (ModelMesh mesh in model.Meshes)
                    mesh.Draw();

                // Undo the renderstate settings from the shader
                GraphicsDevice.BlendState = BlendState.AlphaBlend;
                GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;

                RasterizerState rasterizerState1 = new RasterizerState();
                rasterizerState1.CullMode = CullMode.CullCounterClockwiseFace;
                rasterizerState1.MultiSampleAntiAlias = true;
                GraphicsDevice.RasterizerState = rasterizerState1;
                GraphicsDevice.PresentationParameters.MultiSampleCount = 2;
            }

#if false
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (Effect effect in mesh.Effects)
                {
                    effect.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index] *
                        Matrix.CreateScale(1000) *
                        Matrix.CreateTranslation(activeCamera.Position + new Vector3(0, 0, activeCamera.Distance)));
                    effect.Parameters["Projection"].SetValue(activeCamera.Projection);
                    effect.Parameters["View"].SetValue(activeCamera.View);
                }
                mesh.Draw();
            }
#endif
            base.Draw(gameTime);
        }
    }
}